/*
  +----------------------------------------------------------------------+
  | PHP Version 5                                                        |
  +----------------------------------------------------------------------+
  | Copyright (c) 1997-2013 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP license,      |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author:                                                              |
  +----------------------------------------------------------------------+
*/

/* $Id$ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "main/SAPI.h"  
#include "Zend/zend_interfaces.h"  
#include "ext/standard/php_var.h"  
#include "ext/standard/php_string.h"  
#include "ext/standard/php_smart_str.h" 
#include "ext/standard/php_array.h"
#include "ext/standard/url.h"
#include "ext/standard/php_string.h"
#include "php_wk_framework.h"
#include "wk_view.h"
#include "wk_model.h"
#include "wk_controller.h"
#include "wk_load.h"

zend_class_entry *wk_load_ce;

ZEND_BEGIN_ARG_INFO_EX(void_arginfo, 0, 0, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(construct_arginfo, 0, 0, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(model_arginfo, 0, 0, 0)
ZEND_ARG_INFO(0, filename)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(helper_arginfo, 0, 0, 0)
ZEND_ARG_INFO(0, filename)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(config_arginfo, 0, 0, 0)
ZEND_ARG_INFO(0, filename)
ZEND_END_ARG_INFO()

PHP_METHOD(wk_load, __construct){
}

PHP_METHOD(wk_load, model){
	zval *model_name, *apppath, *model, *controller_instance;
	smart_str filepath = {0};

	if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &model_name) == FAILURE){
		RETURN_FALSE;
	}

	if(Z_TYPE_P(model_name) != IS_STRING){
		zend_error(E_ERROR, "model name must string");
		RETURN_FALSE;
	}

	controller_instance = zend_read_static_property(wk_controller_ce, ZEND_STRL("instance"), 0 TSRMLS_CC);
	model = zend_read_property(Z_OBJCE_P(controller_instance), controller_instance, Z_STRVAL_P(model_name), Z_STRLEN_P(model_name), 0 TSRMLS_CC);
	
	if(Z_TYPE_P(model) == IS_NULL){
		zval *model_obj;
		zend_class_entry *model_ce;

		apppath = zend_read_static_property(wk_framework_ce, ZEND_STRL("apppath"), 0 TSRMLS_CC);
		smart_str_appendl(&filepath, Z_STRVAL_P(apppath), Z_STRLEN_P(apppath));
		smart_str_appendl(&filepath, "models/", 7);
		smart_str_appendl(&filepath,  Z_STRVAL_P(model_name),  Z_STRLEN_P(model_name));
		smart_str_appendl(&filepath, ".php", 4);
		smart_str_0(&filepath);

		include(filepath.c);
		model_ce = get_class_entry(Z_STRVAL_P(model_name),  Z_STRLEN_P(model_name));

		if(model_ce == NULL){
			zend_error(E_ERROR, "%s not found", Z_STRVAL_P(model_name));
			RETURN_FALSE;
		}
		
		MAKE_STD_ZVAL(model_obj);
		object_init_ex(model_obj, model_ce);
		if( zend_hash_exists(&model_ce->function_table, ZEND_STRL("__construct")) ){
			zend_error(E_ERROR, "class %s dose not has function construct!", Z_STRVAL_P(model_name));
			RETURN_FALSE;
		}
		zend_call_method_with_0_params(&model_obj, model_ce, NULL, "__construct", NULL);
		zend_update_property(wk_controller_ce, controller_instance, Z_STRVAL_P(model_name), Z_STRLEN_P(model_name), model_obj TSRMLS_CC);
	}else if(Z_TYPE_P(model) == IS_OBJECT){
		RETURN_ZVAL(model, 1, 0);
	}else{
		zend_error(E_ERROR, "property name %s is already exists!", Z_STRVAL_P(model));
		RETURN_FALSE;
	}
}

PHP_METHOD(wk_load, helper){
	zval *helper_name, *apppath, *helper_arr;
	smart_str filepath = {0};

	if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &helper_name) == FAILURE){
		RETURN_FALSE;
	}

	if(Z_TYPE_P(helper_name) != IS_STRING){
		zend_error(E_ERROR, "model name must string");
		RETURN_FALSE;
	}

	helper_arr = zend_read_property(wk_load_ce, getThis(), "helper", 6, 0 TSRMLS_CC);
	
	if(Z_TYPE_P(helper_arr) == IS_NULL){
		MAKE_STD_ZVAL(helper_arr);
		array_init(helper_arr);
	}else if( !zend_hash_exists(Z_ARRVAL_P(helper_arr), Z_STRVAL_P(helper_name), Z_STRLEN_P(helper_name)) ){
		RETURN_TRUE;
	}

	add_assoc_stringl(helper_arr, Z_STRVAL_P(helper_name), "", 0, 1);

	{
		apppath = zend_read_static_property(wk_framework_ce, ZEND_STRL("apppath"), 0 TSRMLS_CC);
		smart_str_appendl(&filepath, Z_STRVAL_P(apppath), Z_STRLEN_P(apppath));
		smart_str_appendl(&filepath, "helpers/", 8);
		smart_str_appendl(&filepath,  Z_STRVAL_P(helper_name),  Z_STRLEN_P(helper_name));
		smart_str_appendl(&filepath, "_helper.php", 11);
		smart_str_0(&filepath);

		include(filepath.c);
		zend_update_property(wk_load_ce, getThis(), ZEND_STRL("helper"), helper_arr TSRMLS_CC);
		RETURN_TRUE;
	}
}

PHP_METHOD(wk_load, config){
	zval *config_name, *apppath, *config_arr, *config_data, *config_obj, *controller_instance;
	zval **tmp;

	if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &config_name) == FAILURE){
		RETURN_FALSE;
	}

	if(Z_TYPE_P(config_name) != IS_STRING){
		zend_error(E_ERROR, "model name must string");
		RETURN_FALSE;
	}

	controller_instance = zend_read_static_property(wk_controller_ce, ZEND_STRL("instance"), 0 TSRMLS_CC);
	config_obj = zend_read_property(Z_OBJCE_P(controller_instance), controller_instance, ZEND_STRL("config"), 0 TSRMLS_CC);
	config_arr = zend_read_property(Z_OBJCE_P(config_obj), config_obj, ZEND_STRL("config"), 0 TSRMLS_CC);
	
	if( Z_TYPE_P(config_arr) == IS_NULL ){
		MAKE_STD_ZVAL(config_arr);
		array_init(config_arr);
	}

	add_assoc_stringl(config_arr, Z_STRVAL_P(config_name), "", 0, 1);

	{
		smart_str filepath = {0};
		zval **config_data;
		char *config_path;
		smart_str_appendl(&filepath, Z_STRVAL_P(config_name), Z_STRLEN_P(config_name));
		smart_str_appendl(&filepath, ".php", 4);
		smart_str_0(&filepath);

		config_path = get_config_path(filepath.c, filepath.len);
		include(config_path);
		efree(config_path);
		
		if( zend_hash_find( EG(active_symbol_table), "config", 7, (void**)&config_data ) == SUCCESS){
			zval *config;

			if(Z_TYPE_PP(config_data) == IS_ARRAY){
				config = zend_read_property(Z_OBJCE_P(config_obj), config_obj, ZEND_STRL("config"), 0 TSRMLS_CC);
				if(Z_TYPE_P(config) == IS_NULL){
					MAKE_STD_ZVAL(config);
					array_init(config);
				}

				php_array_merge(Z_ARRVAL_P(config), Z_ARRVAL_PP(config_data), 0);
				zend_update_property(Z_OBJCE_P(config_obj), config_obj, ZEND_STRL("config"), config TSRMLS_CC);
			}
		
		}

		zend_update_property(Z_OBJCE_P(config_obj), config_obj, ZEND_STRL("config"), config_arr TSRMLS_CC);
		RETURN_TRUE;
	}
}

static zend_function_entry wk_load_method[] = {
	ZEND_ME(wk_load, __construct, construct_arginfo, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
	ZEND_ME(wk_load, model, model_arginfo, ZEND_ACC_PUBLIC)
	ZEND_ME(wk_load, helper, helper_arginfo, ZEND_ACC_PUBLIC)
	ZEND_ME(wk_load, config, config_arginfo, ZEND_ACC_PUBLIC)
	{NULL, NULL, NULL}
};
 
EXT_STARTUP_FUNCTION(wk_load){
	zend_class_entry wk_load;
	INIT_CLASS_ENTRY(wk_load, "wk_load", wk_load_method);
	wk_load_ce = zend_register_internal_class(&wk_load TSRMLS_CC);
	return SUCCESS;
}